#include "StdAfx.h"
#include "haterb.h"

#ifdef ZEN_BOOST

#include <winsock2.h>
#pragma comment(lib, "ws2_32")
#include <windows.h>

#include "internal/hlog.h"

namespace Zen{namespace utility{

string CreateUUID()
{
	static uuids::random_generator generator;
	return uuids::to_string(generator());
}

bool RemoveEmptyDir(const string& strPath)
{
	bool bCanRemove = true;
	boost::system::error_code ec;
	directory_iterator i(strPath, ec), end;
	while (i != end)
	{
		if (is_directory(i->path(), ec))
		{
			bool bCanRemoveSub = RemoveEmptyDir(i->path().string());
			bCanRemove = bCanRemove && bCanRemoveSub;
		}
		else
		{
			bCanRemove = false;
		}
		++i;        
	}
	if (bCanRemove)
		remove_all(strPath, ec);
	return bCanRemove;
}

string NormalizePath(const string& strPath)
{
	boost::system::error_code ec;
	string ret = strPath;
	replace(ret.begin(), ret.end(), '\\', '/');
	std::transform(ret.begin(), ret.end(), ret.begin(), tolower);
	if (!ret.empty() && *(ret.end()-1) == '/')
		ret.erase(ret.end()-1);
	ret = path(ret).normalize().string();
	replace(ret.begin(), ret.end(), '\\', '/');
	return ret;
}

struct Process 
{
	STARTUPINFOA si;
	PROCESS_INFORMATION pi;
};

ProcessSP InvokeProcess(const string& strCmdLine, const string& strCurDir/*=""*/, bool bShowWindow/*=true*/)
{
	ProcessSP pProc;
	pProc.reset(new Process());
	pProc->si.cb = sizeof(pProc->si);
	pProc->si.dwFlags = STARTF_USESHOWWINDOW;
	pProc->si.wShowWindow = bShowWindow ? SW_SHOW : SW_HIDE;
	LPCSTR pCurDir = strCurDir.empty() ? NULL : strCurDir.c_str();
	if (!::CreateProcessA(NULL, const_cast<char*>(strCmdLine.c_str()), 
		NULL, NULL, FALSE, 0, NULL, pCurDir, &pProc->si, &pProc->pi))
	{
		pProc.reset();
	}
	return pProc;
}

bool WaitForProcess(const ProcessSP pProc, int nMsec)
{
	return WAIT_OBJECT_0 == 
		::WaitForSingleObject(pProc->pi.hProcess, nMsec);
}

bool KillProcess(const ProcessSP pProc, int nExitCode/*=0*/)
{
	return !!::TerminateProcess(pProc->pi.hProcess, nExitCode);
}

string FormatErrorCode(const boost::system::error_code& ec)
{
	return (format("[ev: %1%, cat: %2%, msg: %3%]")
		% ec.value()
		% ec.category().name()
		% ec.message()).str();
}

//static streambuf rbuf;

ostream& Log()
{
	return (ostream&)HLog<clog>(false);
}

ostream& Out()
{
	return (ostream&)HLog<cout>(false);
}

ostream& Err()
{
	return (ostream&)HLog<cerr>(false);
}

ostream& TimedLog()
{
	return (ostream&)HLog<clog>(true);
}

ostream& TimedOut()
{
	return (ostream&)HLog<cout>(true);
}

ostream& TimedErr()
{
	return (ostream&)HLog<cerr>(true);
}

ostream& LogF()
{
	static ofstream log_file("c:\\log.txt", ios::app);
	clog.rdbuf(log_file.rdbuf());
	return (ostream&)HLog<clog>(false);
}

bool rar_exe(const string& strFolderPath, const string& strZipPath, const StringSet& filter, int nLevel/*=0*/)
{
	boost::system::error_code ec;
	path cur_path = current_path();
	bool bIsOK = false;
	if (exists(strFolderPath, ec)) // Path found
	{
		string strRarPath = WrapText(cur_path.string() + "/rar.exe", '\"');
		string strFolderWrap = WrapText(strFolderPath, '\"');
		string strZipWrap = WrapText(strZipPath, '\"');
		create_directories(path(strZipPath).parent_path(), ec);

		string strLevel = StringFormat(20, "-m%d", nLevel);
		const char* pszCmd[]=
		{
			strRarPath.c_str(),
			"a", strZipWrap.c_str(),
			"-r", // Recursive
			"-o-", // Not overwrite
			strLevel.c_str(), // Compression level 0
			// "-df", // Delete after transfer
			"-ed", // No empty directories
		};

		string strCmdLine = pszCmd[0];
		for (int i = 1; i < sizeof(pszCmd)/sizeof(*pszCmd); ++i)
		{
			strCmdLine.push_back(' ');
			strCmdLine += pszCmd[i];
		}

		// Add filters
		for (StringSet::const_iterator 
			i = filter.begin(); i != filter.end(); ++i)
		{
			strCmdLine += " -x*.";
			strCmdLine += *i;
		}

		if (ProcessSP pProc = InvokeProcess(strCmdLine, strFolderPath, false))
		{
			WaitForProcess(pProc, LONG_MAX);
			KillProcess(pProc);
		}
		bIsOK = exists(strZipPath, ec);
	}
	return bIsOK;
}

bool unrar_exe(const string& strFolderPath, const string& strZipPath)
{
	boost::system::error_code ec;
	path cur_path = current_path();
	string strUnrarPath = WrapText(cur_path.string() + "/unrar.exe", '\"');
	string strZipWrap = WrapText(strZipPath, '\"');
	const char* pszCmd[] = 
	{
		strUnrarPath.c_str(),
		"x", // Reserve dir structure
		strZipWrap.c_str(),
		"-o+" // Overwrite
	};

	string strCmdLine = pszCmd[0];
	for (int i = 1; i < sizeof(pszCmd)/sizeof(*pszCmd); ++i)
	{
		strCmdLine.push_back(' ');
		strCmdLine += pszCmd[i];
	}

	if (ProcessSP pProc = InvokeProcess(strCmdLine, strFolderPath, false))
	{
		WaitForProcess(pProc, LONG_MAX);
		KillProcess(pProc);
	}
	return true;
}


}}//end utility//end Zen

#endif